package com.cg.leetcode;

import org.junit.Test;

/**
 * 105.从前序与中序遍历序列构造二叉树
 *
 * @program: LeetCode->LeetCode_105
 * @author: cg
 * @create: 2022-04-25 20:07
 **/
public class LeetCode_105 {

    @Test
    public void test105() {
        System.out.println(buildTree(new int[]{3, 9, 20, 15, 7}, new int[]{9, 3, 15, 20, 7}));
    }

    /**
     * 给定两个整数数组 preorder 和 inorder，其中 preorder 是二叉树的先序遍历， inorder 是同一棵树的中序遍历，请构造二叉树并返回其根节点。
     * <p>
     * 示例 1:
     * 输入: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
     * 输出: [3,9,20,null,null,15,7]
     * <p>
     * 示例 2:
     * 输入: preorder = [-1], inorder = [-1]
     * 输出: [-1]
     * <p>
     * 提示:
     * 1 <= preorder.length <= 3000
     * inorder.length == preorder.length
     * -3000 <= preorder[i], inorder[i] <= 3000
     * preorder 和 inorder 均 无重复 元素
     * inorder 均出现在 preorder
     * preorder 保证 为二叉树的前序遍历序列
     * inorder 保证 为二叉树的中序遍历序列
     *
     * @param preorder
     * @param inorder
     * @return
     */
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        return dfs(preorder, 0, preorder.length, inorder, 0, inorder.length);
    }

    private TreeNode dfs(int[] preorder, int preLeft, int preRight, int[] inorder, int inLeft, int inRight) {
        if (preLeft >= preRight || inLeft >= inRight) {
            return null;
        }
        // 前序遍历中的第一个节点就是根节点
        int rootVal = preorder[preLeft];
        TreeNode root = new TreeNode(rootVal);

        // 在中序遍历中定位根节点
        int rootIndex = 0;
        for (int i = inLeft; i < inRight; i++) {
            if (inorder[i] == rootVal) {
                rootIndex = i;
                break;
            }
        }
        // 得到左子树中的节点数目
        int size = rootIndex - inLeft;
        // 递归地构造左子树，并连接到根节点
        // 先序遍历中「从 左边界+1 开始的 size」个元素就对应了中序遍历中「从 左边界 开始到 根节点定位」的元素
        root.left = dfs(preorder, preLeft + 1, preLeft + size + 1, inorder, inLeft, rootIndex);
        // 递归地构造右子树，并连接到根节点
        // 先序遍历中「从 左边界+1+size 开始到 右边界」的元素就对应了中序遍历中「从 根节点定位+1 到 右边界」的元素
        root.right = dfs(preorder, preLeft + size + 1, preRight, inorder, rootIndex + 1, inRight);
        return root;
    }

}
